#include <utility>
#include <algorithm>
#include "CommandDispatcher.h"
#include "MemTrack.h"

namespace bs
{
	CommandDispatcher::CommandDispatcher()
	{
	}

	CommandDispatcher::~CommandDispatcher()
	{
		for(ProcessorSetMap::iterator itr = this->processors.begin();
			itr!=this->processors.end(); ++itr)
		{
			delete itr->second;
		}

		for(std::list<Command*>::iterator itr=this->commands.begin();
			itr!=this->commands.end(); ++itr)
		{
			delete *itr;
		}
	}

	CommandDispatcher& CommandDispatcher::Instance()
	{
		static CommandDispatcher dispatcher;
		return dispatcher;
	}

	void CommandDispatcher::RegisterCommandType(int type)
	{
		if(this->processors.find(type) == this->processors.end())
		{
			this->processors.insert(std::make_pair(type, new ProcessorSet));
		}
	}

	void CommandDispatcher::RegisterProcessor(int type, ICommandProcessor* processor)
	{
		if(!processor)
			return;

		if(this->processors.find(type) == this->processors.end())
			return;

		this->processors[type]->insert(processor);
	}

	void CommandDispatcher::UnregisterCommandType(int type)
	{
		if(this->processors.find(type) == this->processors.end())
			return;

		delete this->processors[type];
		this->processors.erase(type);
	}

	void CommandDispatcher::UnregisterProcessor(int type, ICommandProcessor* processor)
	{
		if(this->processors.find(type) == this->processors.end())
			return;

		this->processors[type]->erase(processor);
	}

	void CommandDispatcher::UnregisterProcessor(ICommandProcessor* processor)
	{
		for(ProcessorSetMap::iterator itr=this->processors.begin();
			itr!=this->processors.end(); ++itr)
		{
			itr->second->erase(processor);
		}
	}

	void CommandDispatcher::SendCommand(Command* cmd)
	{
		if(!cmd)
			return;

		ProcessorSetMap::iterator itr = this->processors.find(cmd->GetType());
		if(itr != this->processors.end())
		{
			for(ProcessorSet::iterator iter=itr->second->begin();
				iter!=itr->second->end(); ++iter)
			{
				(*iter)->Execute(*cmd);
			}
		}
		
		delete cmd;
	}

	void CommandDispatcher::PostCommand(Command* cmd)
	{
		if(!cmd)
			return;

		this->commands.push_back(cmd);
	}

	void CommandDispatcher::Dispatch()
	{
		while(!this->commands.empty())
		{
			Command* cmd = this->commands.front();
			this->commands.pop_front();
			this->SendCommand(cmd);
		}
	}

}
